package com.cavy.platform.client.service;

import com.cavy.platform.client.domain.DockerEventHandler;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.EventStream;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.Event;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

@Slf4j
public class SpotifyDockerEventServiceImpl implements Runnable, Consumer<Event> {

    public static final String EVENT_THREAD_NAME = "DockerEventHandler";
    private final Thread dockerEventHandlerThread;
    private DockerClient client;
    private EventStream eventStream;
    private Map<String, DockerEventHandler> handlerMap = new HashMap<>();

    public SpotifyDockerEventServiceImpl(DockerClient client) {
        this.client = client;
        dockerEventHandlerThread = new Thread(this);
        dockerEventHandlerThread.setName(EVENT_THREAD_NAME);
        dockerEventHandlerThread.setDaemon(true);
        dockerEventHandlerThread.start();
    }

    @Override
    public void run() {
        try {
            eventStream = client.events();
            eventStream.forEachRemaining(this);
        } catch (DockerException | InterruptedException e) {
            log.error("监听容器事件发生错误,错误类型:{},错误信息:", e.getClass(), e.getMessage());
        }
    }

    @Override
    public void accept(Event event) {
        log.debug("事件:{}", event);
        //排除不是容器的事件
        Event.Type type = event.type();
        if (!Event.Type.CONTAINER.equals(type)) {
            return;
        }
        //排除id为空的事件
        Event.Actor actor = event.actor();
        if (actor == null) {
            return;
        }
        String id = actor.id();
        if (StringUtils.isEmpty(id)) {
            return;
        }
        String action = event.action();
        DockerEventHandler dockerEventHandler = handlerMap.get(id);
        if (dockerEventHandler == null) {
            return;
        }
        DockerContainerEvent containerEvent = DockerContainerEvent.valueOf(action);
        //处理事件
        handlerEvent(containerEvent, dockerEventHandler, event);

    }

    private void handlerEvent(DockerContainerEvent containerEvent, DockerEventHandler dockerEventHandler, Event event) {
        switch (containerEvent) {
            case create:
                dockerEventHandler.createEvent(event);
                break;
            case destroy:
                dockerEventHandler.destroyEvent(event);
                handlerMap.remove(dockerEventHandler.getDockerContainerId());
                break;
            case die:
                dockerEventHandler.dieEvent(event);
                break;
            case kill:
                dockerEventHandler.killEvent(event);
                break;
            case start:
                dockerEventHandler.startEvent(event);
                break;
            case stop:
                dockerEventHandler.stopEvent(event);
                break;
            default:
                log.debug("事件:{}", event);
        }
    }

    public void destroy() {
        dockerEventHandlerThread.interrupt();
        eventStream.close();
    }

    public void registerEventHandler(DockerEventHandler handler) {
        handlerMap.put(handler.getDockerContainerId(), handler);
    }
}
